Tables
Suppose, you want to maintain a large set of objects and you need to access them as fast as possible. Mapping mechanism in Java allows you do this associating a key to each object. Java introduces a concept called Map. A Map is a data structure that's designed for fast lookups. In map, data is stored in key-object pairs with every key being unique. That is, no two objects should have the same key. Each key maps to anobject and hence the name. These pairs are called map entries. With this, the user’s view of storing objects looks like a table as shown in Figure 9.1.
Example:
Key |
Object |
k1 |
o1 |
k2 |
o2 |
k3 |
o2 |
k4 |
o5 |
k5 |
o9 |
k6 |
o6 |
Figure 9.1: Concept of map table in Java
In other words, for an object (o), there is a key (k); mathematically , where h denotes a function. Intuitively, this function h is called a hash function. Thus, map data structure models the function abstraction in mathematics. Figure 9.2 illustrates a map:
Figure 9.2: Map as a mathematical abstraction of function
Some examples of maps
Maps are perfect to use for key-value association mapping such as dictionaries. The maps are used to perform lookups by keys or when someone wants to retrieve and update elements by keys. Some examples are:
· Filenames and their contents stored in a secondary storage place.
· All error codes and their descriptions for a system.
· Zip codes and delivery destinations in a courier service.
· A map of managers and employees. Each manager (key) is associated with a list of employees (value) he manages.
· A map of classes and students. Each class (key) is associated with a list of students (value).
Following are some important characteristics about Map.
1. A map is a mechanism for the fast retrieval of an object.
2. In a map, an entry is characterized with a pair of elements: key and object.
3. Given a key you can find an object. In other words, retrieving an object requires a key to be supplied.
4. The keys must be unique, but the objects may be duplicated.
5. A map cannot contain duplicate keys.
6. Mathematically, map implements an one-to-many and onto association.
Hash function for mapping
For the key-object association, a hash function is required. This hash function, in fact, generates a code called hash code. That is, with , h being the hash function, given an object o, h returns a unique value k. In general, his system dependent and for the internal use of the system.
Example 9.1: Hash functions
A simple hash function is defined as follows.
h(k) = k mod 19
Here, mod is modulo remainder operation. Some examples are:
h(123) = 5
h(99) = 4
h(2014) = 0
Note that in this example, the hash function generates has codes within the rang [0, 1, …, 18] for any integer numbers. Thus, a key k is used to generate a hash code, which determines where in memory the <k, o> pair is stored. This is why a map is also sometime referred as a dictionary because of the way it works.
Note:
· A key can be obtained for any kind of object that you want to use as reference to objects, lke integer, string, any used defined data type, such as Student, Book, etc.
· Since the keys have to uniquely identify the objects, all keys in a map must be different.
· In Java, there is a method called hashCode() defined in the class Object, which produces a hash code of type int for any object. The method as it is implemented in Java, usually it is the memory address where an object is stored. Thus the method always produces distinct hash code for distinct objects.
· Further, you can overwrite the method hashCode() for your own defined class of objects. Here is an example, how you can do that.
Example 9.2: Generating hash
code for a user defined object
class Person {
String firstName;
String lastName;
int age;
Person (String f, String l,
int a) {
firstName = f;
lastname = l;
age = a;
}
public int hashCode() {
return (5*firstName.hashCode()
+ 7 * lastName.hashCode()
+ 11 *age.hashCode() );
}
public static void main(String
args{}) {
P p = new Person(“Rajat”,
“Ray”, 21);
int k = p.hashCode();
System.out.println(p + “has
code “ + k);
}
}
Hierarchy of Map in Java Collection Framework
Java introduces the concept of Map, which is another member in the Java Collection Framework. In Java, a Map is an object that maps keys to values, or is a collection of key-value pairs. It models the function abstraction in mathematics.
In java.uti package, a number of interfaces and classes are defined and declared to support map objects in Java program. A part of the important interfaces and classes is shown in Fig. 9.3.
Figure 9.3: Hierarchy of Map collection
The following are the interfaces declared in java.util package. See Table 9.1.
Description |
|
Map |
Mapsuniquekeystovalues.
The interface is generic and it is defined as interface Map<K, V>,
where K specifies the type of keys, and V specifies the type of values. |
Map.Entry |
Describesanelement(akey/valuepair)inamap.ThisisaninnerclassofMap. |
NavigableMap |
ExtendsSortedMaptohandletheretrievalofentriesbasedonclosest-matchsearches. |
SortedMap |
ExtendsMapsothatthekeysaremaintainedinascendingorder. |
Table 9.1: Interfaces for Map in Java Collection Framework
Table 9.2 lists all the classes which are defined in java.util package.
Description |
|
AbstractMap |
ImplementsmostoftheMapinterface. |
EnumMap |
ExtendsAbstractMapfor
usewith enumkeys. |
HashMap |
ExtendsAbstractMaptouseahashtable. |
TreeMap |
ExtendsAbstractMaptouseatree. |
LinkedHashMap |
ExtendsHashMaptoallowinsertion-orderiterations. |
IdentityHashMap |
ExtendsAbstractMapandusesreferenceequalitywhencomparingdocuments. |
WeakHashMap |
ExtendsAbstractMaptouseahashtablewithweakkeys. |
Table 9.2: The classes for map in Java Collection Framework
In the following, we shall discuss the interfaces and classes for handling map objects.
The Map interface
The methods defined in the Map interface are listed in Table 9.3.
Method |
Description |
void clear() |
Removes all key/value pairs from the invoking map. |
defaultVcompute(Kk,BiFunction<?superK,?superV, ?extendsV>func) |
Callsfunctoconstructanewvalue.Iffuncreturnsnon-null,thenewkey/valuepairisaddedtothemap,anypreexistingpairingisremoved,andthenewvalueisreturned.Iffuncreturnsnull,anypreexistingpairingisremoved,andnullisreturned.
|
defaultVcomputeIfAbsent(Kk,Function<?superK, ?extendsV>func) |
Returnsthevalueassociatedwiththekeyk.Otherwise,thevalueisconstructedthroughacalltofuncandthepairingisenteredintothemapandtheconstructedvalueisreturned.Ifnovaluecanbeconstructed,nullisreturned. |
Default V computeIfPresent(K
k, BiFunction<?superK,?superV, ?extendsV>func) |
Ifkisinthemap,anewvalueisconstructedthroughacalltofuncandthenewvaluereplacestheoldvalueinthemap.Inthiscase,thenewvalueisreturned.Ifthevaluereturnedbyfuncisnull,theexistingkeyandvalueareremovedfromthemapandnullisreturned. |
booleancontainsKey(Objectk) |
Returnstrueiftheinvokingmapcontainskasakey.Otherwise,returnsfalse. |
booleancontainsValue(Objectv) |
Returnstrueifthemapcontainsvasavalue.Otherwise,returnsfalse. |
Set<Map.Entry<K,V>>entrySet() |
ReturnsaSetthatcontainstheentriesinthemap.ThesetcontainsobjectsoftypeMap.Entry.Thus,thismethodprovidesaset-viewoftheinvokingmap. |
booleanequals(Objectobj) |
ReturnstrueifobjisaMapandcontainsthesameentries.Otherwise,returnsfalse. |
defaultvoidforEach(BiConsumer< ?superK, ?superV>action) |
Executesactiononeachelementintheinvokingmap.AConcurrentModificationExceptionwillbethrownifanelementisremovedduringtheprocess. |
Vget(Objectk) |
Returnsthevalueassociatedwiththekeyk.Returns nullifthekeyisnotfound. |
defaultVgetOrDefault(Objectk,VdefVal) |
Returnsthevalueassociatedwithkifitisinthemap.Otherwise,defValisreturned. |
inthashCode() |
Returnsthehashcodefortheinvokingmap. |
booleanisEmpty() |
Returnstrueiftheinvokingmapisempty.Otherwise,returnsfalse. |
Set<K>keySet() |
ReturnsaSetthatcontainsthekeysintheinvokingmap.Thismethodprovidesaset-viewofthekeysintheinvokingmap. |
defaultVmerge(Kk,Vv,BiFunction<?superV,?superV, ?extendsV>func) |
Ifkisnotinthemap,thepairingk,visaddedtothemap.Inthiscase,visreturned.Otherwise,funcreturnsanewvaluebasedontheoldvalue,thekeyisupdatedtousethisvalue,andmerge()returnsthisvalue.Ifthevaluereturnedbyfuncisnull,theexistingkeyandvalueareremovedfromthemapandnullisreturned. |
Vput(Kk,Vv) |
Putsanentryintheinvokingmap,overwritinganypreviousvalueassociatedwiththekey.Thekeyandvaluearekandv,respectively.Returnsnullifthekeydidnotalreadyexist.Otherwise,thepreviousvaluelinkedtothekeyisreturned. |
voidputAll(Map<?extendsK, ?extendsV>m) |
Putsalltheentriesfrommintothismap. |
defaultVputIfAbsent(Kk,Vv) |
Insertsthekey/valuepairintotheinvokingmapifthispairingisnotalreadypresentoriftheexistingvalueisnull.Returnstheoldvalue.Thenullvalueisreturnedwhennopreviousmappingexists,orthevalueisnull. |
Vremove(Objectk) |
Removestheentrywhosekeyequalsk. |
defaultbooleanremove(Objectk,Objectv) |
Ifthekey/valuepairspecifiedbykandvisintheinvokingmap,itisremovedandtrueisreturned.Otherwise,falseisreturned. |
defaultbooleanreplace(Kk,VoldV,VnewV) |
Ifthekey/valuepairspecifiedbykandoldVisintheinvokingmap,thevalueisreplacedbynewVandtrueisreturned.Otherwisefalseisreturned. |
defaultVreplace(Kk,Vv) |
Ifthekeyspecifiedbykisintheinvokingmap,itsvalueissettovandthepreviousvalueisreturned.Otherwise,nullisreturned. |
defaultvoidreplaceAll(BiFunction< ?superK, ?superV, ?extendsV>func) |
Executesfunconeachelementoftheinvokingmap,replacingtheelementwiththeresultreturnedbyfunc.AConcurrentModificationExceptionwillbethrownifanelementisremovedduringtheprocess. |
intsize() |
Returnsthenumberofkey/valuepairsinthemap. |
Collection<V>values() |
Returnsacollectioncontainingthevaluesinthemap.Thismethodprovidesacollection-viewofthevaluesinthemap. |
Table 9.3: Methods declared in Map interface.
Maps revolve around two basic operations: get( ) and put( ). To put a value into a map, use put( ), specifying the key and the value. To obtain a value, call get( ), passing the key as an argument. The value is returned.
Further, you can note that the Map interface is not a subtype of the Collection interface. Therefore, it behaves a bit different from the rest of the collection types, although part of the Collections Framework. However, you can obtain a collection-view of a map. To do this, you can use the entrySet( ) method. It returns a Set that contains the elements in the map. To obtain a collection-view of the keys, use keySet(). To get a collection-view of the values, use the method values( ).
The StoredMap interface
The SortedMap interface extends Map. It ensures that the entries are maintained in ascending order based on the keys. SortedMap is generic like the interface Map. The methods defined in the StoredMap interface are listed in Table 9.4.
Method |
Description |
Comparator<?superK>comparator() |
Returnstheinvokingsortedmap’scomparator.Ifnaturalorderingisusedfortheinvokingmap,nullisreturned. |
KfirstKey() |
Returnsthefirstkeyintheinvokingmap. |
SortedMap<K,V>headMap(Kend) |
Returnsasortedmapforthosemapentrieswithkeysthatarelessthanend. |
KlastKey() |
Returnsthelastkeyintheinvokingmap. |
SortedMap<K,V>subMap(Kstart,Kend) |
Returnsamapcontainingthoseentrieswithkeysthataregreaterthanorequaltostartandlessthanend. |
SortedMap<K,V>tailMap(Kstart) |
Returnsamapcontainingthoseentrieswithkeysthataregreaterthanorequaltostart. |
Table 4: The methods declared in StoredMap interface
The NavigableMap interface
The NavigableMap interface extends SortedMap and declares the behavior of a map that supports the retrieval of entries based on the closest match to a given key or keys. The NavigableMap is also a generic interface like the SortedMap and Map interfaces. The methods defined in the NavigableMap interface are listed in Table 9.5.
Method |
Description |
Map.Entry<K,V>ceilingEntry(Kobj) |
Searchesthemapforthesmallestkeyksuchthat k>=obj.Ifsuchakeyisfound,itsentryisreturned.Otherwise,nullisreturned. |
KceilingKey(Kobj) |
Searchesthemapforthesmallestkeyksuchthatk
>=obj. If sucha key isfound, it isreturned.Otherwise, nullis
returned. |
NavigableSet<K>descendingKeySet() |
ReturnsaNavigableSetthatcontainsthekeysintheinvokingmapinreverseorder.Thus,itreturnsareverseset-viewofthekeys.Theresultingsetisbackedbythemap. |
NavigableMap<K,V>descendingMap() |
ReturnsaNavigableMapthatisthereverseoftheinvokingmap.Theresultingmapisbackedbytheinvokingmap. |
Map.Entry<K,V>firstEntry() |
Returnsthefirstentryinthemap.Thisistheentrywiththeleastkey. |
Map.Entry<K,V>floorEntry(Kobj) |
Searchesthemapforthelargestkeyksuchthatk<=obj.Ifsuchakeyisfound,itsentryisreturned.Otherwise,nullisreturned. |
KfloorKey(Kobj) |
Searchesthemapforthelargestkeyksuchthatk<=obj.Ifsuchakeyisfound,itisreturned.Otherwise,nullisreturned. |
NavigableMap<K,V> headMap(KupperBound,booleanincl) |
ReturnsaNavigableMapthatincludesallentriesfromtheinvokingmapthathavekeysthatarelessthanupperBound.Ifinclistrue,thenanelementequaltoupperBoundisincluded.Theresultingmapisbackedbytheinvokingmap. |
Map.Entry<K,V>higherEntry(K obj) |
Searchesthesetforthelargestkeyksuchthat k>obj.Ifsuchakeyisfound,itsentryisreturned.Otherwise,nullisreturned. |
KhigherKey(Kobj) |
Searchesthesetforthelargestkeyksuchthatk>obj.Ifsuchakeyisfound,itisreturned.Otherwise,nullisreturned. |
Map.Entry<K,V>lastEntry() |
Returnsthelastentryinthemap.Thisistheentrywiththelargestkey. |
Map.Entry<K,V>lowerEntry(Kobj) |
Searchesthesetforthelargestkeyksuchthatk<obj.Ifsuchakeyisfound,itsentryisreturned.Otherwise,nullisreturned. |
K lowerKey(Kobj) |
Searchesthesetforthelargestkeyksuchthatk<obj.Ifsuchakeyisfound,itisreturned.Otherwise,nullisreturned. |
NavigableSet<K>navigableKeySet() |
ReturnsaNavigableSetthatcontainsthekeysintheinvokingmap.Theresultingsetisbackedbytheinvokingmap. |
Map.Entry<K,V>pollFirstEntry() |
Returnsthefirstentry,removingtheentryintheprocess.Becausethemapissorted,thisistheentrywiththeleastkeyvalue.nullisreturnedifthemapisempty. |
Map.Entry<K,V>pollLastEntry() |
Returnsthelastentry, removingtheentryintheprocess.Becausethemapissorted,thisistheentrywiththegreatestkeyvalue.nullisreturnedifthemapisempty. |
NavigableMap<K,V>subMap(KlowerBound, booleanlowIncl,KupperBoundbooleanhighIncl) |
ReturnsaNavigableMapthatincludesallentriesfromtheinvokingmapthathavekeysthataregreaterthanlowerBoundandlessthanupperBound.IflowInclistrue,thenanelementequaltolowerBoundisincluded.IfhighInclistrue,thenanelementequaltohighInclisincluded.Theresultingmapisbackedbytheinvokingmap. |
NavigableMap<K,V> tailMap(KlowerBound,booleanincl) |
ReturnsaNavigableMapthatincludesallentriesfromtheinvokingmapthathavekeysthataregreaterthanlowerBound.Ifinclistrue,thenanelementequaltolowerBoundisincluded.Theresultingmapisbackedbytheinvokingmap. |
Table 9.5: The methods declared in NavigableMap interface
The Map.Entry interface
The Map.Entry interface enables you to work with a map entry. Recall that the entrySet( ) method declared by the Map interface returns a Set containing the map entries. Each of these set elements is a Map.Entry object. Map.Entry is generic and is declared like this: interface Map.Entry<K, V> Here, K specifies the type of keys, and V specifies the type of values. Table 9.6 summarizes the non-static methods declared by Map.Entry.
Method |
Description |
Boolean equals(Object obj) |
Returns true if
obj is a Map.Entry whose
key and value are equal to that of the invoking object. |
K getKey() |
Returns the key for this map entry. |
V getValue() |
Returns the value for this map entry. |
Int hashCode() |
Returns the hash code for this map entry. |
V setValue(V v) |
Sets the value for this map entry
to v. A ClassCastException Is thrown if v is not the correct type for the map.
An IllegalArgumentException is
thrown if there is a problem with v. A NullPointerException is thrown
if v is null and the map does not permit null keys. An UnsupportedOperationException
is thrown if the map cannot be changed. |
Table 9.6: The methods declared in Map.Entry interface
The Map classes
There are several classes (also see Fig. 9.3 and Table 9.2) to implement the map interfaces. All classes extends the AbstractMap class, which in turns implements the Map interface. This implies that all the methods in the Map interface are mostly defined in them in addition to some of their own methods. In the following, a brief description of each class followed by the constructors and methods are briefly discussed. Following this, the utility of each class with reference to the following activities are also discussed.
· Creating a map container
· Storing objects into a map container
· Retrieving objects from a map container
· Removing objects from a map container
· Collection view of a map container
· Bulk operations on a Map container
Following are the basic operations of a Map along with the methods defined in Map framework:
· Association (put)
· Lookup (get)
· Checking (contains Key and contains Value)
· Modification (remove and replace)
· Cardinality (size and isEmpty).
The EnumMap class
This class defines keys of an enum type. It is a generic class that has this declaration:
class EnumMap<K extends Enum<K>, V>
Here, K specifies the type of key, and V specifies the type of value. Notice that K must extend Enum<K>, which enforces the requirement that the keys must be of an enum type.
EnumMap defines the following constructors which is shown in Table 9.7:
Constructor |
Description |
EnumMap(Class<K>kType) |
This constructor
creates an empty EnumMap of type kType. |
EnumMap(Map<K,
? extends V> m) |
This constructor
creates an EnumMap map that contains the same entries as m. |
EnumMap(EnumMap<K,
? extends V>em) |
To create an
EnumMap initialized with the values in em. |
Table 9.7. The constructors in EnumMap class
There are no class of its own defined in EnumMap class.
The HashMap class
This class is used to create a hash table to store the map. The execution of get( ) and put() method can be done in a constant time irrespective of the size of the table because of the use of hash value of key. HashMap is a generic class and it has the following declaration:
class HashMap<K, V>
Here, K specifies the type of keys, and V specifies the type of values.
HashMap defines the following constructors which is shown in Table 9.8:
Constructor |
Description |
HashMap( ) |
This constructor
creates a default hash map. |
HashMap(Map<?
extends K, ? extends V> m) |
The form is to
initialize the hash map using the
elements of m. |
HashMap(int
capacity) |
The third form
initializes the capacity of the hash map to capacity. |
HashMap(int
capacity, float fillRatio) |
The fourth form
initializes both the capacity and fill ratio of the hash map by using its arguments.
The meaning of capacity and fill ratio is the same as for HashSet, described earlier.
The default capacity is 16. The default fill ratio is 0.75. |
Table 9.8. The constructors in HashMap class
Like EnumMap, there is no class of its own defined in HashMap class.
Example 9.3a:
Creating a Map container using HashMap class and storing objects into it
The following example creates a map container using the put() method.
import
java.util.*;
class
HashMapCreateDemo {
public static void main(String args[]) {
// Create a
hash map object as a container.
HashMap<Double,
String>hMap = new HashMap<Double, String>();
// Put
elements to the map container
hMap.put(200.0,
"OK");
hMap.put(303.0,
"See Other");
hMap.put(404.0,
"Not Found");
hMap.put(500.0,
"Internal Server Error");
System.out.println(hMap); // Printing the container
}
}
Note:
·
Alternatively, you could use interface type (Map) to declare the
hashMap object. For example,
Map<String,
Double>hMap = new HashMap<String, Double>();
·
Always use generics and diamond operator to declare a new map.
·
As you can see in the output, a HashMap does not impose any
order on its key-value elements.
·
If you put an object with the same key value, it will overwrite
the previous one.
Example 9.3b: Storing
objects into a Map container using HashMap class with duplicate values
The following example creates a map container using the put() method and with duplicate entries.
import
java.util.*;
class
HashMapDuplicateDemo {
public static void main(String args[]) {
// Create a
hash map object as a container.
HashMap<Integer,
String>hMap = new HashMap<Integer, String>();
// Put
elements to the map container with duplicates
hMap.put(200,
"OK");
hMap.put(303,
"See Other");
hMap.put(404,
"Not Found");
hMap.put(500,
"Internal Server Error");
hMap.put(303,
"Inavlid entry");
hMap.put(101,
"See Other");
System.out.println(hMap); // Printing the container
}
}
Example 9.3c: Creating and storing a Map container using
HashMap class with copy
The following example creates a map container that copies elements from an existing map.
import
java.util.*;
class
HashMapCopyDemo {
public
static void main(String args[]) {
// Create a hash map object as
a container.
Map<String, Double> hMap1
= new HashMap<>();
// Put elements to the map
container
hMap1.put("John Doe",
new Double(3434.34));
hMap1.put("Tom
Smith", new Double(123.22));
hMap1.put("Jane
Baker", new Double(1378.00));
hMap1.put("Tod Hall",
new Double(99.22));
hMap1.put("Ralph
Smith", new Double(-19.08));
System.out.println(hMap1); // Printing the container
// Create a copy of a hMap1 to
hMap2
Map<String,Double> hMap2
= new HashMap<>(hMap1);
// Add data into hMap2
hMap1.put("RobinKeith",
new Double(423.22));
hMap1.put("PeterHwang",
new Double(178.00));
System.out.println(hMap2); // Printing the container
}
}
Example 9.4: Retrieving
objects from a Map container
The following example illustrates how an object stored in a map framework can be accessed. For this, you should use the get().
import
java.util.*;
class
HashMapAcsessDemo {
public static void main(String args[]) {
// Create a
hash map object as a container.
Map<String,
Double>hMap = new HashMap<>();
// Put
elements to the map container
hMap.put("John
Doe", new Double(3434.34));
hMap.put("Tom
Smith", new Double(123.22));
hMap.put("Jane
Baker", new Double(1378.00));
hMap.put("Tod
Hall", new Double(99.22));
hMap.put("Ralph
Smith", new Double(-19.08));
// Deposit
1000 into John Doe's account.
double balance
= hMap.get("John Doe");
hMap.put("John
Doe", balance + 1000);
System.out.println("John
Doe's current balance: " + hMap.get("John Doe"));
}
}
Example 9.5: Removing
objects from a Map container
There are two methods, namely remove() and replace() that you can use for remove an entry in a map framework. The following example illustrates how an object stored in a map framework can be removed.
import
java.util.*;
class
HashMapRemoveDemo {
public static void main(String args[]) {
//
Create a hash map object as a container.
Map<String,
Double>hMap = new HashMap<>();
//
Put elements to the map container
hMap.put("John
Doe", new Double(3434.34));
hMap.put("Tom
Smith", new Double(123.22));
hMap.put("Jane
Baker", new Double(1378.00));
hMap.put("Tod
Hall", new Double(99.22));
hMap.put("Ralph
Smith", new Double(-19.08));
double val = hMap.remove("Jane
Baker");
if (val !=
null) {
System.out.println("Removed
value: " + val);
}
System.out.println(hMap);
hMap.remove("Tod
Hall", 99.22);
System.out.println(hMap);
hMap.replace("Ralph
Smith", 545.67);
System.out.println(hMap);
}
}
Note:
·
The remove(Object key) method removes the mapping for a key from
the map if it is present (we care about only the key, and the value does not
matter). This method returns the value to which the map previously associated
the key, or null if the map doesn’t contain mapping for the key.
·
Similarly, the remove(Object key, Object value) method removes
the mapping of a specified key and specified value, and returns true if the
value was removed. This method is useful in case we really care about the key
and value to be removed.
·
The replace(K key, V value)method replaces the entry for the
specified key only if it is currently mapping to some value. This method
returns the previous value associated with the specified key. Here’s an
example:
Example 9.6a: Viewing a Map container : Status of a map
There are two methods, namely size() and isEmpty() that can be used to check the status of a map container. The following example illustrates how an object stored in a map framework can be viewed.
import
java.util.*;
class
HashMapViewDemo {
public static void main(String args[]) {
//
Create a hash map object as a container.
HashMap<String,
Double>hMap = new HashMap<String, Double>();
//
Put elements to the map container
hMap.put(200, "OK");
hMap.put(303, "See
Other");
hMap.put(404, "Not
Found");
hMap.put(500, "Internal
Server Error");
// Checking
the container
if (hMap.isEmpty())
{
System.out.println("Error:
The container is empty");
} else {
System.out.println(hMap); // Printing the container
}
// Printing
the size of the container
System.out.println(“Size
: “ + hMap.size());
}
}
Example 9.6b: Viewing
a Map container : Map iteration
As a Map is not a true collection, there is no direct method for iterating over a map. Instead, we can iterate over a map using its collection views. Any Map’s implementation has to provide the following four Collection view methods:
keySet(): returns a Set view of the keys contained in the map. Hence we can iterate over the keys of the map.
values(): returns a collection of values contained in the map. Thus we can iterate over values of the map
entrySet(): returns a Set view of the mappings contained in this map. Therefore, we can iterate over mappings in the map using the set view.
forEach()and Lambda expression: Additionally, you
can use the Lambda expressions and the forEach() statement to
view the map container.
The following program illustrates the above here ways f iterating over a map container.
import
java.util.*;
class
HashMapIterationDemo {
public static void main(String args[]) {
//
Create a hash map object as a container.
Map<String,
String>mapCountryCodes = newHashMap<>();
mapCountryCodes.put("1", "USA");
mapCountryCodes.put("44", "United
Kingdom");
mapCountryCodes.put("33", "France");
mapCountryCodes.put("81", "Japan");
mapCountryCodes.put("91", "India");
// Collection view using keySet()
Set<String>setCodes
= mapCountryCodes.keySet();
Iterator<String>
iterator = setCodes.iterator();
while(iterator.hasNext()) {
String code = iterator.next();
String country
= mapCountryCodes.get(code);
System.out.println(code
+ " => "+ country);
}
// Collection view
using values()
Collection<String> countries =
mapCountryCodes.values();
for(String
country : countries) {
System.out.println(country);
}
// Collection view
using entrySet()
Set<Map.Entry<String,
String>> entries =
mapCountryCodes.entrySet();
for(Map.Entry<String,
String>entry : entries) {
String code = entry.getKey();
String country =
entry.getValue();
System.out.println(code
+ " => "+ country);
}
// Collection view
using Lambda expression
mapCountryCodes.forEach((code,
country) ->
System.out.println(code
+ " => "+ country));
}
}
Example 9.7: Performing
Bulk Operations with Maps
There are the following two bulk operations with maps.
clear() : The clear() method removes all mappings from the map. The map will be empty after this method returns.
putAll()
: The putAll(Map<K, V> m) method copies all of the mappings from the
specified map to this map.
Following program illustrates the said two operations with a map
collection.
import
java.util.*;
class
HashMapBulkOperationDemo {
public static void main(String args[]) {
//
Create two map object containers.
Map<Integer, String>countryCodesEU = new
HashMap<>();
countryCodesEU.put(44,
"United Kingdom");
countryCodesEU.put(33, "France");
countryCodesEU.put(49, "Germany");
Map<Integer, String>countryCodesWorld = new
HashMap<>();
countryCodesWorld.put(1,
"United States");
countryCodesWorld.put(86, "China");
countryCodesWorld.put(82, "South Korea");
System.out.println("Before:
" + countryCodesWorld);
// Merger two
containers using putAll()
countryCodesWorld.putAll(countryCodesEU);
System.out.println("After: " + countryCodesWorld);
// Clear one map container
countryCodesEU.clear();
System.out.println("Is
map empty? "+ countryCodesEU.isEmpty());
}
}
The TreeMap class
The TreeMap creates maps stored in a tree structure. A TreeMap provides an efficient means of storingkey/value pairs in sorted order and allows rapid retrieval. You should note that, unlike a hash map, a tree map guarantees that its elements will be sorted in ascending key order.
The TreeMap class extends AbstractMap and implements the NavigableMap interface. TreeMap is a generic class that has this declaration:
class TreeMap<K, V>
Here, K specifies the type of keys, and V specifies the type of values.
TreeMap defines the following constructors which is shown in Table 9.9:
Constructor |
Description |
TreeMap( ) |
The first form
constructs an empty tree map that will be sorted by using the natural order of
its keys. |
TreeMap(Comparator<?
super K> comp) |
The second form
constructs an empty tree-based map that will be sorted by using the
Comparator comp. (Comparators are discussed later in this chapter.) |
TreeMap(Map<?
extends K, ? extends V> m) |
The third form initializes
a tree map with the entries from m, which will be sorted by using the natural
order of the keys.. |
TreeMap(SortedMap<K,
? extends V>sm) |
The fourth form
initializes a tree map with the entries from sm, which will be sorted in the
same order as sm. |
Table 9.9. The constructors in TreeMap class
TreeMap has no map methods beyond those specified by the NavigableMap interface and the AbstractMap class.
Example 9.8: Managing a Map container as a TreeMap class
object
All the operations you have learned for the HashMap class is equally applicable with TreeMap class. The following example illustrates few such operation in a single program.
import
java.util.*;
class
TreeMapDemo {
public static void main(String args[]) {
//
Create a tree map.
TreeMap<String,
Double> tm = new TreeMap<String, Double>();
//
Put elements to the map.
tm.put("John
Doe", new Double(3434.34));
tm.put("Tom
Smith", new Double(123.22));
tm.put("Jane
Baker", new Double(1378.00));
tm.put("Tod
Hall", new Double(99.22));
tm.put("Ralph
Smith", new Double(-19.08));
//
Get a set of the entries.
Set<Map.Entry<String,
Double>> set = tm.entrySet();
//
Display the elements.
for(Map.Entry<String,
Double> me : set) {
System.out.print(me.getKey()
+ ": ");
System.out.println(me.getValue());
}
System.out.println();
//
Deposit 1000 into John Doe's account.
double
balance = tm.get("John Doe");
tm.put("John
Doe", balance + 1000);
System.out.println("John
Doe's new balance: " +
tm.get("John
Doe"));
}
}
The LinkedHashMap class
It maintains a linked list of the entries in the map, in the order in which they were inserted. This allows insertion-order iteration over the map. That is, when iterating through a collection-view of a LinkedHashMap, the elements will be returned in the order in which they were inserted. You can also create a LinkedHashMap that returns its elements in the order in which they were last accessed. LinkedHashMap is a generic class that has this declaration:
class LinkedHashMap<K, V>
Here, K specifies the type of keys, and V specifies the type of values.
LinkedHashMap extends HashMap. LinkedHashMap defines the following constructors which is shown in Table 9.10:
Constructor |
Description |
LinkedHashMap( ) |
It is a default
constructor. |
LinkedHashMap(Map<?
extends K, ? extends V> m) |
This constructor
initializes the LinkedHashMap with the elements from m. |
LinkedHashMap(int
capacity) |
The third form
initializes the capacity. |
LinkedHashMap(int
capacity, float fillRatio) |
initializes both
capacity and fill ratio. The default capacity is 16. The default ratio is
0.75. |
LinkedHashMap(int
capacity, float fillRatio, boolean Order) |
Itallows you to
specify whether the elements will be stored in the linked list by insertion order,
or by order of last access. If Order is true, then access order is used. If
Order is false, then insertion order is used. |
Table 9.10: The constructors in LinkedHashMap class
LinkedHashMap adds only one method to
those defined by HashMap. This method is removeEldestEntry(), and it is shown
here:
protected
booleanremoveEldestEntry(Map.Entry<K, V> e)
This method is used keep a track of
whether the map removes any eldest entry from the map. So each time a new
element is added to the LinkedHashMap, the eldest entry is removed from the
map. This method is generally invoked after the addition of the elements into the
map by the use of put() and putall() method. This method is called by put( )
and putAll( ). The oldest entry is passed in e. By default, this method returns
false and does nothing. However, if you override this method, then you can have
the LinkedHashMap remove the oldest entry in the map. To do this, have your
override return true. To keep the oldest entry, return false.
Example
9.9: Managing a Map
container as a LinkedHashMap class object
The following program illustrates the creation of a Map object using LinkedHashMap class.
import
java.util.*;
class
LinkedHashMapDemo {
//
Refers to the max size of the map following which the removal takes place
//
of the eldest entry
private
static final int MAX = 6;
public static void main(String args[]) {
//
Creating the linked hashmap and
implementing removeEldestEntry()
// to MAX size
LinkedHashMap<Integer,
String>lhm =
new
LinkedHashMap<Integer, String>() {
protected
booleanremoveEldestEntry(Map.Entry<Integer, String>
eldest) {
return size() > MAX;
}
};
// Adding elements
using put()
lhm.put(0,
"Welcome");
lhm.put(1,
"To");
lhm.put(2,
"The");
lhm.put(3,
"World");
lhm.put(4,
"Of");
lhm.put(5, "Java");
System.out.println(""
+ lhm);
// Adding more elements
lhm.put(6, "Joy
with Java");
// Displying the map
after adding one more element
System.out.println(""
+ lhm);
// Adding more elements
lhm.put(7,
"Hello");
// Displying the map
after adding one more element
System.out.println(""
+ lhm);
}
}
Note:
·
This method allows the map to
modify itself as directed by its return value. Although the method is permitted
to modify the map directly, if it does so, it must return false which will be
indicative of the fact that the map should not attempt any further modification
leading to ambiguity. The effects of returning true after modifying the map
from within this method are unspecified.
·
This is very useful when the map
represents a cache where it allows the map to reduce memory consumption by
deleting stale entries one after another.
Example 9.10
: Map container with user defined data type
All the examples can be extended
to be applied to any class either built-in or user defined. The following
example illustrates how a map container will be with objects of Book class.
import
java.util.*;
class Book
{
int
id;
String
name,author,publisher;
int
quantity;
public
Book(int id, String n, String a, String p, int q){
this.id = id;
name = n;
author = a;
publisher = p;
quantity = q;
}
}
public class
MapBookDataExample {
public
static void main(String[] args) {
//Creating map of Books
Map<Integer,Book> map=new
LinkedHashMap<Integer,Book>();
//Creating Books
Book b1=new
Book(101,"Python","Ponting","Oxford",8);
Book b2=new Book(102,"Java","Spielberg","McGraw
Hill",4);
Book b3=new Book(103,"C++","Galvin","Wiley",6);
//Adding Books to
map
map.put(2,b2);
map.put(1,b1);
map.put(3,b3);
//Traversing map
for(Map.Entry<Integer,
Book>entry:map.entrySet()){
int key=entry.getKey();
Book b=entry.getValue();
System.out.println(key+"
Details:");
System.out.println(b.id+" "+b.name+"
"+b.author+"
"+b.publisher+"
"+b.quantity);
}
}
}
The IdentityHashMap class
The API documentation explicitly states that IdentityHashMap is not for general use and hence its discussion is ignored.
The IdentityHashMap class
WeakHashMap implements a map that uses “weak keys,” which allows an element in a map to be garbage-collected when its key is otherwise unused. This class is also not used for general use and is not discussed.
Note:
·
AbstractMapis a superclass for all concrete map implementations.
· There are three interfaces for implementing Map in java: Map, SortedMap and NavigableMap, and four classes: EnumMap, HashMap, TreeMap and LinkedHashMap.
· Map don’t implement the Iterable interface. This means that you cannot cycle through a map using a for-each style for loop. Furthermore, you can’t obtain an iterator to a map.
· You can obtain a collection-view of a map, which does allow the use of either the for loop or an iterator.
Example 9.11: A Map container using EnumMap class
The following Java program
illustrates working of EnumMap and its functions.
import
java.util.EnumMap;
public
class Example {
public enum SIZE {S, M, L, X };
public static void main(String args[]) {
// Creating EnumMap in java with
key as enum type STATE
EnumMap<SIZE, String>enuMap = new
EnumMap<SIZE, String>(SIZE.class);
//Putting values inside EnumMap in Java
// Inserting Enum keys different
from their natural order
enuMap.put(SIZE.S,
"Children");
enuMap.put(SIZE.M, "Young");
enuMap.put(SIZE.L, "Aged");
enuMap.put(SIZE.X, "Old");
// Printing size of EnumMap in java
System.out.println("Size of
EnumMap in java: "+ enuMap.size());
// Printing Java EnumMap
System.out.println("EnumMap:
"+ enuMap);
// Retrieving value from EnumMap in
java
System.out.println("Key : "+
SIZE.S +" Value: " +
enuMap.get(SIZE.S));
}
}
Note:
· EnumMap class is a member of the Java Collections Framework & is not synchronized.
· EnumMap is ordered collection and they are maintained in the natural order of their keys( natural order of keys means the order on which enum constant are declared inside enum type )
· It’s a high performance map implementation, much faster than HashMap.
· All keys of each EnumMap instance must be keys of a single enum type.
· EnumMap doesn’t allow null key and throw NullPointerException, at same time null values are permitted.
Concurrent Map
Unlike the legacy Hashtable which is synchronized, the HashMap, TreeMap and LinkedHashMap are not synchronized. If thread-safe is priority, consider using ConcurrentHashMap in place of HashMap. Or we can use the Collections.synchronizedMap() utility method that returns a synchronized (thread-safe) map backed by the specified map.
Example 9.12: Thread safe execution with HashMap collection
import
java.util.*;
class
HashMapSynchronizationDemo {
public static void main(String args[]) {
//
Create two map object containers.
Map<Integer, String> map =
Collections.synchronizedMap(new HashMap<>());
// Creatin a map
map.put(400, "Bad
Request");
map.put(304, "Not
Modified");
map.put(200, "OK");
map.put(301, "Moved
Permanently");
map.put(500, "Internal
Server Error");
Set<Integer>keySet
= map.keySet();
synchronized(map)
{
Iterator<Integer>
iterator = keySet.iterator();
while(iterator.hasNext())
{
Integer key =
iterator.next();
String value =
map.get(key);
}
}
}
}
Note:
·
You
should manually
synchronize the map when iterating over any of its collection views.
·
If you use your own type for the key and value
(e.g. Student or Employee), the key class and value class must
implement the equals() and hashCode() methods
properly so that the map can look up them correctly.